/**
 * @file    MethodsCommon.h
 * @brief   Defines some common Method implementations
 *
 ****************************************************************************
 * @version 0.8.499 $Id: MethodsCommon.h 2826 2010-08-02 10:13:45Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR MethodRequestS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_MethodsCommon_H__
 #define __WOSH_Core_MethodsCommon_H__

 #include <woshDefs.h>
 #include <core/MethodT.h>
 #include <core/Message.h>
 #include <core/Request.h>
 #include <core/Response.h>


namespace wosh {

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

 #define _METHOD_List						"list"
 #define _METHOD_Retrieve					"retrieve"
 #define _METHOD_RetrieveObject				"retrieve_obj"

 #define _METHOD_GetProperty				"prop_get"
 #define _METHOD_SetProperty				"prop_set"
 #define _METHOD_DelProperty				"prop_del"
 #define _METHOD_ListProperties				"prop_list"
 #define _METHOD_GetPropertiesProvider		"properties_get"

 #define _METHOD_SetProperties				"props_set"
 #define _METHOD_GetProperties				"props_get"

 #define _METHOD_ChMod						"chmod"
 #define _METHOD_ChOwn						"chown"

 #define _METHOD_Dump						"dump"

 #define _METHOD_ListMethods				"method_list"

 #define _METHOD_ListInterfaces				"interface_list"
 #define _METHOD_GetInterfacesProvider		"interface_get"
	
 #define _METHOD_ListRequirements			"requirements_list"
 #define _METHOD_GetRequirementsProvider	"requirements_get"

 #define _METHOD_Man						"man"

////////////////////////////////////////////////////////////////////////////////////////////////

class LogContext;

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Most Generic Method: Message* FUNCTION ( const Message* )

typedef MethodT<const Message*, MethodRunner, Message*>::MethodTPtr MethodMessagePtr;

class MethodMessage : public MethodT<const Message*, MethodRunner, Message*>
 {
	WOSH_CLASSNAME(wosh::MethodMessage)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodMessage( const std::string& Name );
		MethodMessage( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodMessage() { }

	public:
		Message* exec( const Message* requestMessage );

}; // class def


////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Classic Method: Response* FUNCTION ( const Request* )

typedef MethodT<const Request*, MethodRunner, Response*>::MethodTPtr MethodRequestPtr;

class MethodRequest : public MethodT<const Request*, MethodRunner, Response*>
 {
	WOSH_CLASSNAME(wosh::MethodRequest)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodRequest( const std::string& Name );
		MethodRequest( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodRequest() { }

	public:
		Message* exec( const Message* requestMessage );

}; // class def


////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Method which need Message context: Response* FUNCTION ( const Message* )

typedef MethodT<const Message*, MethodRunner, Response*>::MethodTPtr MethodMessageResponsePtr;

class MethodMessageResponse : public MethodT<const Message*, MethodRunner, Response*>
 {
	WOSH_CLASSNAME(wosh::MethodMessageResponse)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodMessageResponse( const std::string& Name );
		MethodMessageResponse( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodMessageResponse() { }

	public:
		// explicit
		void setMethod( MethodRunner* pare, MethodMessageResponsePtr fptr );
		Message* exec( const Message* message );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Simplest Method: WRESULT FUNCTION ()

typedef WRESULT (MethodRunner::*MethodWRESULTPtr)();

class MethodWRESULT : public Method
 {
	WOSH_CLASSNAME(wosh::MethodWRESULT)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodWRESULT( const std::string& Name );
		MethodWRESULT( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodWRESULT() { }

//@}
/** @name Execution and Validation
 * @{
 ******************************************************************************/
	public:
		Message* exec( const Message* requestMessage );
//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setMethod( MethodRunner* pare, MethodWRESULTPtr fptr );
//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		bool isLinkedFunction() const				{ return (this->smMethodTPointer != NULL); }
		bool isLinkedParent() const					{ return (this->parent != NULL); }
//@}
	protected:
		MethodRunner* parent;				///< parent of the method (usually it's the object implementing it)
		MethodWRESULTPtr smMethodTPointer;	///< real function pointer

		void clear();
		short compare(const Method& other) const;

}; // class def


////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Dummy Method: void FUNCTION ()

typedef void (MethodRunner::*MethodVoidPtr)();

class MethodVoid : public Method
 {
	WOSH_CLASSNAME(wosh::MethodVoid)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodVoid( const std::string& Name );
		MethodVoid( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodVoid() { }

//@}
/** @name Execution and Validation
 * @{
 ******************************************************************************/
	public:
		Message* exec( const Message* requestMessage );
//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setMethod( MethodRunner* pare, MethodVoidPtr fptr );
//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		bool isLinkedFunction() const				{ return (this->smMethodTPointer != NULL); }
		bool isLinkedParent() const					{ return (this->parent != NULL); }
//@}
	protected:
		MethodRunner* parent;				///< parent of the method (usually it's the object implementing it)
		MethodVoidPtr smMethodTPointer;	///< real function pointer

		void clear();

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Classic Method: Response* FUNCTION ( const Request* )

typedef MethodT<const SecurityToken*, MethodRunner, WRESULT>::MethodTPtr MethodWRESULTwSecurityTokenPtr;

class MethodWRESULTwSecurityToken : public MethodT<const SecurityToken*, MethodRunner, WRESULT>
 {
	WOSH_CLASSNAME(wosh::MethodWRESULTwSecurityToken)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodWRESULTwSecurityToken( const std::string& Name );
		MethodWRESULTwSecurityToken( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodWRESULTwSecurityToken() { }

	public:
		Message* exec( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class MethodNULL : public Method
 {
	WOSH_CLASSNAME(wosh::MethodNULL)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodNULL( const std::string& Name ) : Method(Name) { }

	public:
		Message* exec( const Message* )			{ return NULL; }

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class IDataFieldExtractor;

class MethodList : public Method
 {
	WOSH_CLASSNAME(wosh::MethodList)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodList( const std::string& Name );
		MethodList( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodList();

	public:
		Message* exec( const Message* requestMessage );

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

	public:
		void setDataFieldExtractor( IDataFieldExtractor* extractor );

	protected:
		IDataFieldExtractor* extractor;

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class IItemExtractor;

class MethodRetrieve : public Method
 {
	WOSH_CLASSNAME(wosh::MethodRetrieve)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodRetrieve( const std::string& Name );
		MethodRetrieve( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() );
		virtual ~MethodRetrieve();

	public:
		Message* exec( const Message* requestMessage );

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

	public:
		void setItemExtractor( IItemExtractor* extractor );

	protected:
		IItemExtractor* extractor;

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

template <class OBJECT_TYPE>
class MethodRetrieveObject : public Method
 {
	WOSH_CLASSNAME(wosh::MethodRetrieveObject)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodRetrieveObject( const std::string& Name )
			: Method(Name), object(NULL), accessMutex(NULL), objectPerms(NULL) { }
		MethodRetrieveObject( const std::string& Name, const std::string& Description, const Permission& Perm = Permission::R_XR_XR__() )
			: Method(Name, Description, Perm), object(NULL), accessMutex(NULL), objectPerms(NULL) { }
		virtual ~MethodRetrieveObject() { }

	public:
		Message* exec( const Message* requestMessage ) {
			if ( requestMessage == NULL || requestMessage->isEmpty() ) return NULL;
			if ( !requestMessage->getContent()->isRequest() ) return NULL;
			const Request* request = requestMessage->getContent()->asRequest();
			if ( request == NULL ) return NULL;
			///@todo eval permissions vs. this->objectPerms
			Response* result = new Response( this->name );
			if ( this->object == NULL )
				result->setData( NULL );
			else {
				if ( this->accessMutex != NULL )
					this->accessMutex->lockForRead();
				result->setData( this->object->clone() );
				if ( this->accessMutex != NULL )
					this->accessMutex->unLock();
			 }
			Message* reply = requestMessage->replyTo( result );
			return reply;
		 }

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

	public:
		void configure( const OBJECT_TYPE* object_ref, const MutexRW* mutex_ref = NULL, const Permission* perm_ref = NULL )	{
			this->object = object_ref; this->accessMutex = mutex_ref; this->objectPerms = perm_ref;
		 }
		void configureObject( const OBJECT_TYPE* object_ref, const MutexRW* mutex_ref = NULL )	{
			this->object = object_ref; this->accessMutex = mutex_ref;
			if ( object_ref != NULL )
				this->objectPerms = &object_ref->getPermission();
		 }
		void setObject( const OBJECT_TYPE* object_ref )		{ this->object = object_ref; }
		void setMutex( const MutexRW* mutex_ref )			{ this->accessMutex = mutex_ref; }
		void setPermission( const Permission* perm_ref )	{ this->objectPerms = perm_ref; }

	protected:
		const OBJECT_TYPE* object;
		const MutexRW* accessMutex;
		const Permission* objectPerms;

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class MethodsProvider;
class PropertiesProvider;
class LogContext;

class MethodPropertyT : public Method
 {
	WOSH_CLASSNAME(wosh::MethodPropertyT)

	public:
		MethodPropertyT( const std::string& Name );
		MethodPropertyT( const std::string& Name, const std::string& Description, const Permission& Perm );
		virtual ~MethodPropertyT() { }

		static WRESULT createMethods( MethodsProvider* provider, PropertiesProvider* properties, LogContext* log );

	public:
		Message* exec( const Message* requestMessage );

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

	protected:
		virtual Response* execRequest( const Message* requestMessage ) = 0;

	public:
		void setPropertiesProvider( PropertiesProvider* properties );
		void setLogContext( LogContext* log );

	protected:
		PropertiesProvider* properties;
		LogContext* log;

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodPropertyDel : public MethodPropertyT
 {
	WOSH_CLASSNAME(wosh::MethodPropertyDel)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodPropertyDel( const std::string& Name = _METHOD_DelProperty,
							const std::string& Description = "Delete Property",
							const Permission& Perm = Permission::R_XR__R__() )
			: MethodPropertyT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodPropertySet : public MethodPropertyT
 {
	WOSH_CLASSNAME(wosh::MethodPropertySet)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodPropertySet( const std::string& Name = _METHOD_SetProperty,
							const std::string& Description = "Set Property",
							const Permission& Perm = Permission::R_XR_XR__() )
			: MethodPropertyT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodPropertiesSet : public MethodPropertyT
 {
	WOSH_CLASSNAME(wosh::MethodPropertiesSet)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodPropertiesSet( const std::string& Name = _METHOD_SetProperties,
							const std::string& Description = "Set Properties",
							const Permission& Perm = Permission::R_XR_XR__() )
			: MethodPropertyT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodPropertyGet : public MethodPropertyT
 {
	WOSH_CLASSNAME(wosh::MethodPropertyGet)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodPropertyGet( const std::string& Name = _METHOD_GetProperty,
							const std::string& Description = "Get Property",
							const Permission& Perm = Permission(Permission::RX) )
			: MethodPropertyT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodPropertiesGet : public MethodPropertyT
 {
	WOSH_CLASSNAME(wosh::MethodPropertiesGet)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodPropertiesGet( const std::string& Name = _METHOD_GetProperties,
							const std::string& Description = "Get Properties",
							const Permission& Perm = Permission(Permission::RX) )
			: MethodPropertyT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class Object;

class MethodChT : public Method
 {
	WOSH_CLASSNAME(wosh::MethodChT)

	public:
		MethodChT( const std::string& Name );
		MethodChT( const std::string& Name, const std::string& Description, const Permission& Perm );
		virtual ~MethodChT() { }

		static WRESULT createMethods( MethodsProvider* provider, Object* object, PropertiesProvider* properties, LogContext* log );

	public:
		Message* exec( const Message* requestMessage );

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return (this->object != NULL); }

	protected:
		virtual Response* execRequest( const Message* requestMessage ) = 0;

	public:
		void setObject( Object* object );
		void setPropertiesProvider( PropertiesProvider* properties );
		void setMethodsProvider( MethodsProvider* methods );
		void setLogContext( LogContext* log );

	protected:
		PropertiesProvider* properties;
		MethodsProvider* methods;
		Object* object;
		LogContext* log;

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////

class MethodChMod : public MethodChT
 {
	WOSH_CLASSNAME(wosh::MethodChMod)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodChMod( const std::string& Name = _METHOD_ChMod,
							const std::string& Description = "Change permission",
							const Permission& Perm = Permission::R_XR__R__() )
			: MethodChT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );

}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class MethodChOwn : public MethodChT
 {
	WOSH_CLASSNAME(wosh::MethodChOwn)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodChOwn( const std::string& Name = _METHOD_ChOwn,
							const std::string& Description = "Change ownership",
							const Permission& Perm = Permission::R_XR__R__() )
			: MethodChT(Name, Description, Perm) { }

	protected:
		Response* execRequest( const Message* requestMessage );


}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

class MethodDump : public Method
 {
	WOSH_CLASSNAME(wosh::MethodDump)
	WOSH_CLASS_ABSTRACT(false)

	public:
		MethodDump( const std::string& Name = _METHOD_Dump,
							const std::string& Description = "Dump data",
							const Permission& Perm = Permission::R_XR_XR__() )
			: Method(Name, Description, Perm), log(NULL) { }

	public:
		Message* exec( const Message* requestMessage );

		inline bool isLinkedFunction() const	{ return false; }
		inline bool isLinkedParent() const		{ return false; }

	public:
		void setLogContext( LogContext* log );

	protected:
		Response* execRequest( const Message* requestMessage );

	protected:
		LogContext* log;


}; // class def

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////




}; // namespace wosh

#endif //__WOSH_Core_MethodsCommon_H__
